using System;
using System.Collections.Generic;
using System.Text;

namespace EuropeEngulfed.NET
{
    class RemotePlayer : IPlayer
    {
        private TCPServer tcpServer;
        private GameController.playerType remotePlayerType;

        public RemotePlayer(TCPServer tcpServer, GameController.playerType remotePlayerType)
        {
            this.remotePlayerType = remotePlayerType;
            this.tcpServer = tcpServer;
        }

        private string GetWindowTitleStringAccordingToClientMessage(TCPServer.ServerRequestMessage expectedServerMessage)
        {
            switch(expectedServerMessage)
            {
                case TCPServer.ServerRequestMessage.AskForBreakThroughOptionReturn:
                    return "Waiting for Player Breakthrough Option";
                case TCPServer.ServerRequestMessage.AskForDefenderOptionsReturn:
                    return "Waiting for Defender Combat Options";
                case TCPServer.ServerRequestMessage.AskForGSUCombatCasualtiesReturn:
                    return "Waiting for GSU Combat Casualties";
                case TCPServer.ServerRequestMessage.AssignLossesReturn:
                    return "Waiting for Player to Assign losses";
                case TCPServer.ServerRequestMessage.CounterAttackReturn:
                    return "Waiting for CounterAttack Option";
                case TCPServer.ServerRequestMessage.DoDefenderCombatReturn:
                    return "Waiting for Defender to Complete Combat";
                case TCPServer.ServerRequestMessage.DoStrategicUBoatWarfareReturn:
                    return "Waiting for U-boat Warfare To Complete";
                case TCPServer.ServerRequestMessage.MovesReturn:
                    return "Waiting for Player to complete moves";
                case TCPServer.ServerRequestMessage.ProductionMovesReturn:
                    return "Waiting for Player to complete Production Moves";
                case TCPServer.ServerRequestMessage.StratWarfareReturn:
                    return "Waiting for Player to choose Strat Warfare Options";
                default:
                    return "Waiting For Remote Player";
            }
        }

        private void WaitForRemoteResponse(TCPServer.ServerRequestMessage clientMessageExpected)
        {
            string previousWindowTitle = EuropeEngulfedNETForm.MainForm.ToolStripText;
            EuropeEngulfedNETForm.MainForm.ToggleUIMode(true);
            EuropeEngulfedNETForm.MainForm.ToolStripText = previousWindowTitle + " - " + GetWindowTitleStringAccordingToClientMessage(clientMessageExpected);
            while (!this.tcpServer.ClientResponded(clientMessageExpected))
            {
                System.Threading.Thread.Sleep(50);
                System.Windows.Forms.Application.DoEvents();
            }
            EuropeEngulfedNETForm.MainForm.ToolStripText = previousWindowTitle;
            EuropeEngulfedNETForm.MainForm.ToggleUIMode(false);
        }

        public bool InformPlayerOfChangeOfPhase(GameController.playerType player, GameTurn.GameDate gameDate, GameTurn.GameSubPhase gameSubPhase, GameState gameStateToUpdate)
        {
            ServerMessage message = new ServerMessageInformPlayerOfChangeOfPhase(player, gameDate, gameSubPhase, gameStateToUpdate);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public bool DisplayWeatherDetermination(GameController.playerType player, GameState.Weather southernWeather, GameState.Weather westernWeather, GameState.Weather easternWeather, MapInfo.gameDateWeatherType weatherType, uint axisDieRoll, uint alliedDieRoll)
        {
            ServerMessage message = new DisplayWeather(player, southernWeather, westernWeather, easternWeather, weatherType, axisDieRoll, alliedDieRoll);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public void DisplayCalculatingSupply(GameController.playerType player)
        {
            this.tcpServer.SetServerMessageToSend(new ServerMessageDisplayCalculatingSupply(player));
        }

        public List<StratWarfareMove> DoStrategicBombingWarfare(GameController.playerType player,
        uint originalWesternAlliedBombers, uint originalWesternAlliedFighters, uint WesternAlliedFlak, uint originalGermanBombers,
        uint originalGermanFighters, uint GermanFlak, uint targetedWERPProduction, GameState.Weather currentWesternWeather,
        GameTurn.GameDate currentGameDate, GameTurn.GamePhase currentGamePhase,
        bool upgradedEscorts, bool upgradeBombers)
        {
            ServerMessage message = new ServerMessageDoStrategicBombingWarfare(player, originalWesternAlliedBombers, originalWesternAlliedFighters, WesternAlliedFlak, originalGermanBombers, originalGermanFighters, GermanFlak, targetedWERPProduction, currentWesternWeather, currentGameDate, currentGamePhase, upgradedEscorts, upgradeBombers);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageDoStrategicBombingWarfareReturn)
            {
                return ((ClientMessageDoStrategicBombingWarfareReturn)this.tcpServer.ClientMessageReceived).stratWarfareMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public bool ReportStrategicBombingWarfare(GameController.playerType player,
        uint originalWesternAlliedBombers, uint originalWesternAlliedFighters, uint WesternAlliedFlak, uint originalGermanBombers,
        uint originalGermanFighters, uint GermanFlak, uint targetedWERPProduction, GameState.Weather currentWesternWeather,
        GameTurn.GameDate currentGameDate, GameTurn.GamePhase currentGamePhase,
        bool upgradedEscorts, bool upgradeBombers,
        bool operationOverlord, int numEscortsShotDown, int numInterceptorsShotDownByEscorts, int numInterceptorsShotDownByBombers, int numBombersShotDownByInterceptors, int numBombersShotDownByFlak, int numStrategicBombHits)
        {
            ServerMessage message = new ServerMessageReportStrategicBombingWarfare(player, originalWesternAlliedBombers, originalWesternAlliedFighters, WesternAlliedFlak, originalGermanBombers, originalGermanFighters, GermanFlak, targetedWERPProduction, currentWesternWeather, currentGameDate, currentGamePhase, upgradedEscorts, upgradeBombers, operationOverlord, numEscortsShotDown, numInterceptorsShotDownByEscorts, numInterceptorsShotDownByBombers, numBombersShotDownByInterceptors, numBombersShotDownByFlak, numStrategicBombHits);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public StratWarfareMove DoStrategicUBoatWarfare(int numGermanUBoats, int numBritishASWLevel, int UKWERPProduction)
        {
            ServerMessage message = new ServerMessageDoStrategicUBoatWarfare(numGermanUBoats, numBritishASWLevel, UKWERPProduction);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageDoStrategicUBoatWarfareReturn)
            {
                return ((ClientMessageDoStrategicUBoatWarfareReturn)this.tcpServer.ClientMessageReceived).stratWarfareMove;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public bool ReportStrategicUBoatWarfare(int numGermanUBoats, int numBritishASWLevel, int UKWERPProduction, int numASWHits, int numWERPHits)
        {
            ServerMessage message = new ServerMessageReportStrategicUBoatWarfare(numGermanUBoats, numBritishASWLevel, UKWERPProduction, numASWHits, numWERPHits);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<StratWarfareMove> DoStrategicVWeaponWarfare(int numV1s, int numV2s, int numFigthers, int flakLevel, int WERPs)
        {
            ServerMessage message = new ServerMessageDoStrategicVWeaponWarfare(numV1s, numV2s, numFigthers, flakLevel, WERPs);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageDoStrategicBombingWarfareReturn)
            {
                return ((ClientMessageDoStrategicBombingWarfareReturn)this.tcpServer.ClientMessageReceived).stratWarfareMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public bool ReportStrategicVWeaponWarfare(int numV1s, int numV2s, int numFigthers, int flakLevel, int WERPs,
                                          int numV1sLaunched, int numV2sLaunched, int NumV1sShotDownByFighters, int NumV1sShotDownByFlak, int numWERPsShotDownByV1s, int numWERPsShotDownByV2s)
        {
            ServerMessage message = new ServerMessageReportStrategicVWeaponWarfare(numV1s, numV2s, numFigthers, flakLevel, WERPs, numV1sLaunched, numV2sLaunched, NumV1sShotDownByFighters, NumV1sShotDownByFlak, numWERPsShotDownByV1s, numWERPsShotDownByV2s);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<ProductionMove> DoAxisProductionPhase(Dictionary<MapInfo.CountryID, List<Region>> countryValidSupplySources, int germanInitialWERPS, int ItalianInitialWERPS, int strategicWarfareLosses, int germanFleetMaintenance, int italianFleetMaintenance, int startingGermanSpecialActions, int maxGermanSpecialActions, int startingItalianSpecialActions, int maxItalianSpecialActions, bool germanFleetBuildAvailable, bool italianFleetBuildAvailable, bool FlakBuildable, bool V1BuildAvailable, bool V2BuildAvailable, bool PloestiRestrictionsInEffect, List<GameState.ForcePoolAdjustment> listOfForcePoolAdjustments)
        {
            ServerMessage message = new ServerMessageDoAxisProductionPhase(countryValidSupplySources, germanInitialWERPS, ItalianInitialWERPS, strategicWarfareLosses, germanFleetMaintenance, italianFleetMaintenance, startingGermanSpecialActions, maxGermanSpecialActions, startingItalianSpecialActions, maxItalianSpecialActions, germanFleetBuildAvailable, italianFleetBuildAvailable, FlakBuildable, V1BuildAvailable, V2BuildAvailable, PloestiRestrictionsInEffect, listOfForcePoolAdjustments);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageProductionMovesReturn)
            {
                return ((ClientMessageProductionMovesReturn)this.tcpServer.ClientMessageReceived).listOfProductionMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<ProductionMove> DoAlliedProductionPhase(Dictionary<MapInfo.CountryID, List<Region>> countryValidSupplySources, int UKInitialWERPS, int frenchInitialWERPS, int USSRInitialWERPS, int USAInitialWERPS, int strategicWarfareLosses, int UKFleetMaintenance, int frenchFleetMaintenance, int USSRFleetMaintenance, int startingUKSpecialActions, int startingFrenchSpecialActions, int startingUSSRSpecialActions, int maxUSSRSpecialActions, int startingUSASpecialActions, int maxUSASpecialActions, bool UKFleetBuildAvailable, bool frenchFleetBuildAvailable, bool USAFleetBuildAvailable, bool USSRFleetBuildAvailable, bool FlakBuildable, bool ASWBuildAvailable, bool USAtWar, bool USSRAtWar, int lendLeaseFromUSAForUK, int lendLeaseFromUSAForUSSR, int maxBritishWERPsToUSSR, bool britishLendLeaseToUSSRHalved, int russianEmergencyConscriptionSteps, bool russianCadreBonusInEffect, bool russianProductionPenalty, bool britishProductionPenalty, bool russianEliteInfantryReinforcements, List<GameState.ForcePoolAdjustment> listOfForcePoolAdjustments, GameController.UKLendLease ukLendLease)
        {
            ServerMessage message = new ServerMessageDoAlliedProductionPhase(countryValidSupplySources, UKInitialWERPS, frenchInitialWERPS, USSRInitialWERPS, USAInitialWERPS, strategicWarfareLosses, UKFleetMaintenance, frenchFleetMaintenance, USSRFleetMaintenance, startingUKSpecialActions, startingFrenchSpecialActions, startingUSSRSpecialActions, maxUSSRSpecialActions, startingUSASpecialActions, maxUSASpecialActions, UKFleetBuildAvailable, frenchFleetBuildAvailable, USAFleetBuildAvailable, USSRFleetBuildAvailable, FlakBuildable, ASWBuildAvailable, USAtWar, USSRAtWar, lendLeaseFromUSAForUK, lendLeaseFromUSAForUSSR, maxBritishWERPsToUSSR, britishLendLeaseToUSSRHalved, russianEmergencyConscriptionSteps, russianCadreBonusInEffect, russianProductionPenalty, britishProductionPenalty, russianEliteInfantryReinforcements, listOfForcePoolAdjustments, ukLendLease);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageProductionMovesReturn)
            {
                return ((ClientMessageProductionMovesReturn)this.tcpServer.ClientMessageReceived).listOfProductionMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public bool AskForStrategicWarfareInterception(GameController.playerType player)
        {
            ServerMessage message = new ServerMessageAskForStrategicWarfareInterception(player);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<SupplySelectionMove> DoSupplySelection(GameController.playerType player, bool finalSupply, Dictionary<MapInfo.RegionID, Dictionary<MapInfo.CountryID, List<GameController.SeaSupplySolution>>> regionsCountryOOSorUSingSeaToReturn, Dictionary<MapInfo.RegionID, int> seaSupplyPoints)
        {
            ServerMessage message = new ServerMessageDoSupplySelection(player, finalSupply, regionsCountryOOSorUSingSeaToReturn, seaSupplyPoints);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<SupplySelectionMove> supplySelectionMoves = new List<SupplySelectionMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach(Move move in listOfMoves)
                {
                    supplySelectionMoves.Add((SupplySelectionMove)move);
                }

                return supplySelectionMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<OperationalMove> DoInitialOps(GameController.playerType player)
        {
            ServerMessage message = new ServerMessageDoInitialOps(player);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<OperationalMove> opMoves = new List<OperationalMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    opMoves.Add((OperationalMove)move);
                }

                return opMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<OperationalMove> DoBreakThroughOps(GameController.playerType player, List<MapInfo.CountryID> countriesSpendingSA)
        {
            ServerMessage message = new ServerMessageDoBreakThroughOps(player, countriesSpendingSA);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<OperationalMove> opMoves = new List<OperationalMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    opMoves.Add((OperationalMove)move);
                }

                return opMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<StrategicMove> DoInitialStrategicMovement(GameController.playerType player)
        {
            ServerMessage message = new ServerMessageDoInitialStrategicMovement(player);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<StrategicMove> stratMoves = new List<StrategicMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    stratMoves.Add((StrategicMove)move);
                }

                return stratMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<DeploymentMove> DoNewCountryDeployment(GameController.playerType player, MapInfo.CountryID country)
        {
            ServerMessage message = new ServerMessageDoNewCountryDeployment(player, country);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<DeploymentMove> deployMoves = new List<DeploymentMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    deployMoves.Add((DeploymentMove)move);
                }

                return deployMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public bool AskForNavalInterception(GameController.playerType player, SeaMoveOperationalMove seaMove)
        {
            ServerMessage message = new ServerMessageAskForNavalInterception(player, seaMove);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public bool ReportNavalInterception(GameController.playerType player, MapInfo.RegionID regionID, int numFriendlyHitsOn6, int numFriendlyHitsOn56, int numEnemyHitsOn6, int numEnemyHitsOn56, List<PlayingPiece> piecesTransported, List<PlayingPiece> piecesLost)
        {
            ServerMessage message = new ServerMessageReportForNavalInterception(player, regionID, numFriendlyHitsOn6, numFriendlyHitsOn56, numEnemyHitsOn6, numEnemyHitsOn56, piecesTransported, piecesLost);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public CombatMove DoBreakThroughCombat(GameController.playerType player, List<MapInfo.CountryID> countriesSpendingSA, bool followingFromBreakThroughOps, MapInfo.RegionID breakThroughOpsRegion)
        {
            ServerMessage message = new ServerMessageDoBreakThroughCombat(player, countriesSpendingSA, followingFromBreakThroughOps, breakThroughOpsRegion);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                return (CombatMove)listOfMoves[0];
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<CombatMove> DoInitialCombatPhase(GameController.playerType player)
        {
            ServerMessage message = new ServerMessageDoInitialCombatPhase(player);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<CombatMove> combatMoves = new List<CombatMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    combatMoves.Add((CombatMove)move);
                }

                return combatMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public GameController.defenderOptions AskDefenderForDefenderOptions(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool selectGSUs, bool breakThroughCombat, bool assault, List<MapInfo.CountryID> countriesSpendingSA, List<CombatMove> combatMovesAlreadyTaken)
        {
            ServerMessage message = new ServerMessageAskForDefenderOptions(defendingPlayer, regionID, selectGSUs, breakThroughCombat, assault, countriesSpendingSA, combatMovesAlreadyTaken);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if(this.tcpServer.ClientMessageReceived is ClientMessageAskForDefenderOptionsReturn)
            {
                return ((ClientMessageAskForDefenderOptionsReturn)this.tcpServer.ClientMessageReceived).defenderOptions;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public Dictionary<MapInfo.CountryID, int> AskForGSUCombatCasualties(GameController.playerType playerAssigningCasualties, GameController.playerType defendingPlayer, MapInfo.RegionID regionID, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, List<int> defendingDieRolls, List<int> attackingDieRolls, bool breakThrough, List<MapInfo.CountryID> countriesSpendingSA)
        {
            ServerMessage message = new ServerMessageAskForGSUCombatCasualties(playerAssigningCasualties, defendingPlayer, regionID, defendingGSUSelections, attackingGSUSelections, defendingDieRolls, attackingDieRolls, breakThrough, countriesSpendingSA);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageAskForGSUCombatCasualtiesReturn)
            {
                return ((ClientMessageAskForGSUCombatCasualtiesReturn)this.tcpServer.ClientMessageReceived).listOfGSUCombatCasualties;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public Dictionary<PlayingPiece, int> DoDefenderCombat(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSAForBreakThroughCombat, List<CombatMove> combatMovesAlreadyTaken)
        {
            ServerMessage message = new ServerMessageDoDefenderCombat(defendingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, counterAttack, countriesSpendingSAForBreakThroughCombat, combatMovesAlreadyTaken);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageDoDefenderCombatReturn)
            {
                return ((ClientMessageDoDefenderCombatReturn)this.tcpServer.ClientMessageReceived).defenderCombatReturn;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public Dictionary<PlayingPiece, int> AskAttackerToAssignLosses(GameController.playerType attackingPlayer, MapInfo.RegionID regionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<MapInfo.CountryID> countriesSpendingSAInBattle, List<CombatMove> combatMovesAlreadyTaken)
        {
            ServerMessage message = new ServerMessageAskAttackerToAssignLosses(attackingPlayer, regionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, countriesSpendingSAInBattle, combatMovesAlreadyTaken);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageAssignLossesReturn)
            {
                return ((ClientMessageAssignLossesReturn)this.tcpServer.ClientMessageReceived).losses;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public Dictionary<PlayingPiece, int> AskDefenderToAssignLosses(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegionID, bool assault, Dictionary<MapInfo.CountryID, int> defendingGSUSelections, Dictionary<MapInfo.CountryID, int> attackingGSUSelections, int numInfantryLosses, int numArmorLosses, bool counterAttack, List<CombatMove> combatMovesAlreadyTaken)
        {
            ServerMessage message = new ServerMessageAskDefenderToAssignLosses(defendingPlayer, battleRegionID, assault, defendingGSUSelections, attackingGSUSelections, numInfantryLosses, numArmorLosses, counterAttack, combatMovesAlreadyTaken);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageAssignLossesReturn)
            {
                return ((ClientMessageAssignLossesReturn)this.tcpServer.ClientMessageReceived).losses;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<OperationalMove> AskDefenderForRetreatBeforeCombatMoves(GameController.playerType defendingPlayer, MapInfo.RegionID regionID, List<CombatMove> combatMovesAlreadyTaken)
        {
            ServerMessage message = new ServerMessageAskDefenderForRetreatBeforeCombatMoves(defendingPlayer, regionID, combatMovesAlreadyTaken);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<OperationalMove> opMoves = new List<OperationalMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    opMoves.Add((OperationalMove)move);
                }

                return opMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public GameController.defenderCounterAttackOptions AskDefenderForCounterAttack(GameController.playerType defendingPlayer, MapInfo.RegionID battleRegion, List<CombatMove> combatMovesAlreadyTaken)
        {
            ServerMessage message = new ServerMessageAskDefenderForCounterAttack(defendingPlayer, battleRegion, combatMovesAlreadyTaken);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageDefenderCounterAttackOptionsReturn)
            {
                return ((ClientMessageDefenderCounterAttackOptionsReturn)this.tcpServer.ClientMessageReceived).counterAttackOptions;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public GameController.breakThroughSelection AskForBreakThroughOption(GameController.playerType player, bool canBreakthroughCombat)
        {
            ServerMessage message = new ServerMessageAskForBreakThroughOption(player, canBreakthroughCombat);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageAskForBreakThroughOptionReturn)
            {
                return ((ClientMessageAskForBreakThroughOptionReturn)this.tcpServer.ClientMessageReceived).breakThroughSelection;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<StrategicMove> DoBreakThroughStrategicMovement(GameController.playerType player)
        {
            ServerMessage message = new ServerMessageDoBreakThroughStrategicMovement(player);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<StrategicMove> stratMoves = new List<StrategicMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    stratMoves.Add((StrategicMove)move);
                }

                return stratMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public void InformPlayerOfConquest(GameController.playerType player, MapInfo.CountryID country)
        {
            this.tcpServer.SetServerMessageToSend(new ServerMessageInformPlayerOfConquest(player, country));
        }

        public List<FleetTransferMove> DoFleetPointTransfers(GameController.playerType player)
        {
            ServerMessage message = new ServerMessageDoFleetPointTransfers(player);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<FleetTransferMove> fleetMoves = new List<FleetTransferMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    fleetMoves.Add((FleetTransferMove)move);
                }

                return fleetMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public List<MovePieceOperationalMove> DoFortressOverStackMoves(GameController.playerType player, MapInfo.RegionID regionID, int numBlocksToMove)
        {
            ServerMessage message = new ServerMessageDoFortressOverStackMoves(player, regionID, numBlocksToMove);
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<MovePieceOperationalMove> opMoves = new List<MovePieceOperationalMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    opMoves.Add((MovePieceOperationalMove)move);
                }

                return opMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public bool AskAxisPlayerForVichy()
        {
            ServerMessage message = new ServerMessageAskAxisPlayerForVichy();
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageBoolReturn)
            {
                return ((ClientMessageBoolReturn)this.tcpServer.ClientMessageReceived).returnValue;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public void InformPlayer(GameController.playerType player, string information)
        {
            this.tcpServer.SetServerMessageToSend(new ServerMessageInformPlayer(player, information));
        }

        public List<SovietUpFrontDefenseRedeploymentMove> DoAxisRedeploymentOfSovietUpFrontDefenses()
        {
            ServerMessage message = new ServerMessageDoAxisRedeploymentOfSovietUpFrontDefenses();
            this.tcpServer.SetServerMessageToSend(message);
            WaitForRemoteResponse(message.ServerMessageExpected);
            if (this.tcpServer.ClientMessageReceived is ClientMessageMovesReturn)
            {
                List<SovietUpFrontDefenseRedeploymentMove> sovietUpFrontRedeploymentMoves = new List<SovietUpFrontDefenseRedeploymentMove>();
                List<Move> listOfMoves = ((ClientMessageMovesReturn)this.tcpServer.ClientMessageReceived).listOfMoves;
                foreach (Move move in listOfMoves)
                {
                    sovietUpFrontRedeploymentMoves.Add((SovietUpFrontDefenseRedeploymentMove)move);
                }

                return sovietUpFrontRedeploymentMoves;
            }
            else
            {
                throw new InvalidOperationException();
            }
        }

        public void InformPlayerOfVictory(GameController.playerType player, GameController.Victory victory)
        {
            this.tcpServer.SetServerMessageToSend(new ServerMessageInformPlayerOfVictory(player, victory));
        }
    }
}
